package com.game.common.eventsystem;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GameEventDispatchAnnotationManager {
    private Logger logger = LoggerFactory.getLogger(GameEventDispatchAnnotationManager.class);
    private Map<String, List<GameEventListenerMapping>> gameEventMapping = new HashMap<>();

    /**
     * 初始化GameEventDispatchAnnotationManager
     * @param context
     */
    public void init(ApplicationContext context) {
        // 从ApplicationContext中获取所有标记GameEventService注解的bean
        context.getBeansWithAnnotation(GameEventService.class).values().forEach(bean -> {
            Method[] methods = bean.getClass().getMethods(); // 获取bean的所有方法
            for (Method method : methods) {
                GameEventListener  gameEventListener = method.getAnnotation(GameEventListener.class);
                if (gameEventListener != null) {
                    Class<? extends IGameEventMessage> eventClass = gameEventListener.value();
                    GameEventListenerMapping gameEventListenerMapping = new GameEventListenerMapping(bean, method);
                    this.addGameEventListenerMapping(eventClass.getName(), gameEventListenerMapping);
                }
            }
        });
    }

    /**
     * 将GameEventListenerMapping添加到gameEventMapping中
     * @param key
     * @param gameEventListenerMapping
     */
    private void addGameEventListenerMapping(String key,
                                             GameEventListenerMapping gameEventListenerMapping) {
        List<GameEventListenerMapping> gameEventListenerMappings = this.gameEventMapping.get(key);
        if (CollectionUtils.isEmpty(gameEventListenerMappings)) {
            gameEventListenerMappings = new ArrayList<>();
            this.gameEventMapping.put(key, gameEventListenerMappings);
        }
        gameEventListenerMappings.add(gameEventListenerMapping);
    }

    /**
     * 发送事件到事件处理方法中
     * @param gameEventMessage
     * @param origin
     */
    public void sendGameEvent(IGameEventMessage gameEventMessage, Object origin) {
        String key = gameEventMessage.getClass().getName();
        List<GameEventListenerMapping> gameEventListenerMappings = this.gameEventMapping.get(key);
        // 找到监听这个事件的所有方法
        if (!CollectionUtils.isEmpty(gameEventListenerMappings)) {
            // 依次调用事件处理方法
            gameEventListenerMappings.forEach(gameEventListenerMapping -> {
                try {
                    // 通过反射调用事件处理方法
                    gameEventListenerMapping.getMethod()
                            .invoke(
                                    gameEventListenerMapping.getBean(),
                                    origin,
                                    gameEventMessage
                            );
                } catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    logger.error("事件发送失败", e);
                    throw new IllegalArgumentException("事件发送失败", e);
                }
            });
        }
    }
}
